import { IShaderBase } from "../base_frame/IShaderBase";
import { ShaderBase } from "../base_frame/ShaderBase";
import { Vector3 } from "../base_frame/math/Vector3";

export class OutLine extends ShaderBase implements IShaderBase {

    protected readonly VS: string =
        "attribute vec4 a_Position;\n" +
        "attribute vec4 a_Normal;\n" +
        "uniform float u_LineWidth;\n" +
        "uniform mat4 u_MvpMatrix;\n" +
        "void main(){\n" +
        "   gl_Position = u_MvpMatrix * a_Position + normalize(a_Normal)*u_LineWidth;\n" +
        "   gl_Position.x = gl_Position.x + 0.5;\n" +
        "   gl_Position = gl_Position;\n" +
        "}\n";

    protected readonly FS: string =
        "#ifdef GL_ES\n" +
        "precision mediump float;\n" +
        "#endif\n" +
        "uniform vec3 u_LineColor;\n" +
        "void main(){\n" +
        "   gl_FragColor = vec4(u_LineColor, 0.0);\n" +
        "}\n";

    protected a_Position: number;
    protected a_Normal: number;
    protected u_LineWidth: WebGLUniformLocation;
    protected u_LineColor: WebGLUniformLocation;
    count: number;

    indiceBuffer: WebGLBuffer;
    posBuffer: WebGLBuffer;
    id: number = 0;
    normalBuffer: WebGLBuffer;

    init(gl: WebGL2RenderingContext | WebGLRenderingContext): void {
        this.program = createProgram(gl, this.VS, this.FS);
        if (!this.program) return console.error("创建程序对象失败，初始化失败");
        this.gl.useProgram(this.program);
        this.initRef(gl);
        this.initValue(gl);
        this.count = this.initBuffer(gl) as number;
    }

    initValue(gl: WebGL2RenderingContext | WebGLRenderingContext) {
        gl.uniform1f(this.u_LineWidth, 0.2);
        gl.uniform3fv(this.u_LineColor, (new Vector3(1.0, 1.0, 1.0)).toArray());
    }

    initRef(gl: WebGL2RenderingContext | WebGLRenderingContext) {
        this.u_LineWidth = gl.getUniformLocation(this.program, "u_LineWidth");
        this.u_LineColor = gl.getUniformLocation(this.program, "u_LineColor");
        this.a_Position = gl.getAttribLocation(this.program, "a_Position");
        this.a_Normal = gl.getAttribLocation(this.program, "a_Normal");
    }

    initBuffer(gl: WebGL2RenderingContext | WebGLRenderingContext) {
        //顶点坐标
        //      L4------L5 
        //      /|       /|
        //    L0------L1  |
        //     | |     |  |
        //     | L6----|-L7 
        //     | /     | /
        //    L2------L3 
        var vertices = new Float32Array([   // Vertex coordinates
            1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1, 1,    // v0-v1-v2-v3 front
            1, 1, 1, 1, -1, 1, 1, -1, -1, 1, 1, -1,    // v0-v3-v4-v5 right
            1, 1, 1, 1, 1, -1, -1, 1, -1, -1, 1, 1,    // v0-v5-v6-v1 up
            -1, 1, 1, -1, 1, -1, -1, -1, -1, -1, -1, 1,    // v1-v6-v7-v2 left
            -1, -1, -1, 1, -1, -1, 1, -1, 1, -1, -1, 1,    // v7-v4-v3-v2 down
            1, -1, -1, -1, -1, -1, -1, 1, -1, 1, 1, -1     // v4-v7-v6-v5 back
        ]);

        // // Texture coordinates
        // var texCoords = new Float32Array([
        //     1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,    // v0-v1-v2-v3 front
        //     0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0,    // v0-v3-v4-v5 right
        //     1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 0.0, 0.0,    // v0-v5-v6-v1 up
        //     1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,    // v1-v6-v7-v2 left
        //     0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0,    // v7-v4-v3-v2 down
        //     0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0     // v4-v7-v6-v5 back
        // ]);
        // Texture coordinates
        var texCoords = new Float32Array([
            1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,    // v0-v1-v2-v3 front
            1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,    // v0-v1-v2-v3 front
            1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,    // v0-v1-v2-v3 front
            1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,    // v0-v1-v2-v3 front
            1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0,    // v0-v1-v2-v3 front
            1.0, 1.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0   // v0-v1-v2-v3 front
        ]);

        var indices = new Uint8Array([       // Indices of the vertices
            0, 1, 2, 0, 2, 3,    // front
            4, 5, 6, 4, 6, 7,    // right
            8, 9, 10, 8, 10, 11,    // up
            12, 13, 14, 12, 14, 15,    // left
            16, 17, 18, 16, 18, 19,    // down
            20, 21, 22, 20, 22, 23     // back
        ]);

        var normals = new Float32Array([        // normals of the vertices
            0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, // v0-v1-v2-v3
            1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // v0-v3-v4-v5
            0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, // v0-v5-v6-v1 up
            -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, // v1-v6-v7-v2 left
            0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, // v7-v4-v3-v2 down
            0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0, 0.0, 0.0, -1.0 //v4-v7-v6-v5 back
        ]);

        if (!(this.posBuffer = this.createBuffer(gl, this.a_Position, 3, vertices, gl.FLOAT))) return -1;
        if (!(this.normalBuffer = this.createBuffer(gl, this.a_Normal, 3, normals, gl.FLOAT))) return -1;
        let buffer = gl.createBuffer();
        gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, buffer);
        gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, indices, gl.STATIC_DRAW);
        this.indiceBuffer = buffer;
        return indices.length;
    }

    protected createBuffer(gl: WebGL2RenderingContext | WebGLRenderingContext, index: number, size: number, data: any, type: number): WebGLBuffer {
        let buffer = gl.createBuffer();
        if (!buffer) return buffer;
        gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
        gl.bufferData(gl.ARRAY_BUFFER, data, gl.STREAM_DRAW);
        gl.vertexAttribPointer(index, size, type, false, 0, 0);
        gl.enableVertexAttribArray(index);
        return buffer;
    }

    inputBlur(text: string): void {
        // throw new Error("Method not implemented.");
    }

    draw(gl: WebGL2RenderingContext | WebGLRenderingContext): void {
        gl.drawElements(gl.TRIANGLES, this.count, gl.UNSIGNED_BYTE, 0);
    }

}